#include "dev_st7789.h"
#include "device_port.h"
#include <string.h>

// ST7789命令
typedef enum ST7789_DC
{
   ST7789_CMD,
   ST7789_DATA,
}ST7789_DC_t;

// 拉低CS
#define ST7789_CS_LOW() pstST7789->HW.pfnWriteCS(IO_STATUS_LOW)

// 拉高CS
#define ST7789_CS_HIGH() pstST7789->HW.pfnWriteCS(IO_STATUS_HIGH)

// 拉低DC
#define ST7789_DC_LOW() pstST7789->HW.pfnWriteDC(IO_STATUS_LOW)

// 拉高DC
#define ST7789_DC_HIGH() pstST7789->HW.pfnWriteDC(IO_STATUS_HIGH)

#define ST7789_BL_LOW() pstST7789->HW.pfnWriteBL(IO_STATUS_LOW)
#define ST7789_BL_HIGH() pstST7789->HW.pfnWriteBL(IO_STATUS_HIGH)

#define ST7789_RST_LOW() pstST7789->HW.pfnWriteRST(IO_STATUS_LOW)
#define ST7789_RST_HIGH() pstST7789->HW.pfnWriteRST(IO_STATUS_HIGH)

static uint8_t 
dev_st7789_send_byte(Dev_ST7789_t* pstST7789, uint8_t u8Data, ST7789_DC_t eDC)
{
   ST7789_CS_LOW();
 
   (eDC == ST7789_DATA) ? ST7789_DC_HIGH() : ST7789_DC_LOW();
 
   uint8_t u8Ret =pstST7789->HW.pfnSpiTransmit(&u8Data,1);

   ST7789_CS_HIGH();

   return u8Ret;
}

static uint8_t 
dev_st7789_send_half_word(Dev_ST7789_t* pstST7789, uint16_t u16Data)
{
   uint8_t u8Data[2];
   ST7789_CS_LOW();
   ST7789_DC_HIGH();
 
   u8Data[0] = u16Data >> 8;
   u8Data[1] = u16Data & 0xFF;
 
   uint8_t u8Ret =pstST7789->HW.pfnSpiTransmit(u8Data,2);

   ST7789_CS_HIGH();

   return u8Ret;
}
 
static uint8_t
dev_st7789_send_multi_byte(Dev_ST7789_t* pstST7789, uint8_t* pu8Data, uint32_t u32Len)
{
   ST7789_CS_LOW();
   ST7789_DC_HIGH();
 
   uint8_t u8Ret =pstST7789->HW.pfnSpiTransmit(pu8Data,u32Len);

   ST7789_CS_HIGH();

   return u8Ret;
}
 
static uint8_t 
dev_st7789_address_set(Dev_ST7789_t* pstST7789, uint16_t u16XStart,
                      uint16_t u16YStart,uint16_t u16XEnd,uint16_t u16YEnd)
{
	if(ST7789_ROTATION==0)
	{
		dev_st7789_send_byte(pstST7789, 0x2a, ST7789_CMD);//列地址设置
		dev_st7789_send_half_word(pstST7789, u16XStart);
		dev_st7789_send_half_word(pstST7789, u16XEnd);
		dev_st7789_send_byte(pstST7789, 0x2b, ST7789_CMD);//行地址设置
		dev_st7789_send_half_word(pstST7789, u16YStart);
		dev_st7789_send_half_word(pstST7789, u16YEnd);
		dev_st7789_send_byte(pstST7789, 0x2c, ST7789_CMD);//储存器写
	}
// 	else if(ST7789_ROTATION == 90)
// 	{
      
// 		dev_st7789_send_byte(pstST7789, 0x2a, ST7789_CMD);//列地址设置
// 		ST7789_SendHalfWord(x1);
// 		ST7789_SendHalfWord(x2);
// 		dev_st7789_send_byte(pstST7789, 0x2b, ST7789_CMD);//行地址设置
// 		ST7789_SendHalfWord(y1);
// 		ST7789_SendHalfWord(y2);
// 		dev_st7789_send_byte(pstST7789, 0x2c, ST7789_CMD);//储存器写
// 	}
// 	else if(ST7789_ROTATION == 180)
// 	{
//       y1 += 80;
// 	   y2 += 80;
// 		dev_st7789_send_byte(pstST7789, 0x2a, ST7789_CMD);//列地址设置
// 		ST7789_SendHalfWord(x1);
// 		ST7789_SendHalfWord(x2);
// 		dev_st7789_send_byte(pstST7789, 0x2b, ST7789_CMD);//行地址设置
// 		ST7789_SendHalfWord(y1);
// 		ST7789_SendHalfWord(y2);
// 		dev_st7789_send_byte(pstST7789, 0x2c, ST7789_CMD);//储存器写
// 	}
// 	else if(ST7789_ROTATION == 270)
// 	{
//       x1 += 80;
//       x2 += 80;
// 		dev_st7789_send_byte(pstST7789, 0x2a, ST7789_CMD);//列地址设置
// 		ST7789_SendHalfWord(x1);
// 		ST7789_SendHalfWord(x2);
// 		dev_st7789_send_byte(pstST7789, 0x2b, ST7789_CMD);//行地址设置
// 		ST7789_SendHalfWord(y1);
// 		ST7789_SendHalfWord(y2);
// 		dev_st7789_send_byte(pstST7789, 0x2c, ST7789_CMD);//储存器写
// 	}
//    else
//    {
//    }
    return 0;
}

Dev_Ret_t
dev_st7789_init(Dev_ST7789_t *pstST7789){
   // 打开背光
   ST7789_BL_LOW();
   ST7789_BL_HIGH();

   // 拉高CS
   ST7789_CS_HIGH();

   // RST屏幕
   ST7789_RST_LOW();
   DEV_DELAY_MS(1);
   ST7789_RST_HIGH();
   DEV_DELAY_MS(120);

   dev_st7789_send_byte(pstST7789, 0x11, ST7789_CMD);	

   dev_st7789_send_byte(pstST7789, 0x3A, ST7789_CMD);			
   dev_st7789_send_byte(pstST7789, 0x55, ST7789_DATA);   //   5 565  6 666

   dev_st7789_send_byte(pstST7789, 0xB2, ST7789_CMD);			
   dev_st7789_send_byte(pstST7789, 0x0C, ST7789_DATA);
   dev_st7789_send_byte(pstST7789, 0x0C, ST7789_DATA); 
   dev_st7789_send_byte(pstST7789, 0x00, ST7789_DATA); 
   dev_st7789_send_byte(pstST7789, 0x33, ST7789_DATA); 
   dev_st7789_send_byte(pstST7789, 0x33, ST7789_DATA); 			

   dev_st7789_send_byte(pstST7789, 0xB7, ST7789_CMD);			
   dev_st7789_send_byte(pstST7789, 0x35, ST7789_DATA);

   dev_st7789_send_byte(pstST7789, 0xBB, ST7789_CMD);			
   dev_st7789_send_byte(pstST7789, 0x32, ST7789_DATA); //Vcom=1.35V
                                          
   dev_st7789_send_byte(pstST7789, 0xC2, ST7789_CMD);			
   dev_st7789_send_byte(pstST7789, 0x01, ST7789_DATA);

   dev_st7789_send_byte(pstST7789, 0xC3, ST7789_CMD);			
   dev_st7789_send_byte(pstST7789, 0x19, ST7789_DATA); //GVDD=4.8V 
                                          
   dev_st7789_send_byte(pstST7789, 0xC4, ST7789_CMD);			
   dev_st7789_send_byte(pstST7789, 0x20, ST7789_DATA); //VDV, 0x20:0v

   dev_st7789_send_byte(pstST7789, 0xC6, ST7789_CMD);			
   dev_st7789_send_byte(pstST7789, 0x0F, ST7789_DATA); //0x0F:60Hz        	

   dev_st7789_send_byte(pstST7789, 0xD0, ST7789_CMD);			
   dev_st7789_send_byte(pstST7789, 0xA4, ST7789_DATA);
   dev_st7789_send_byte(pstST7789, 0xA1, ST7789_DATA); 											  												  																								
         
   dev_st7789_send_byte(pstST7789, 0xE0, ST7789_CMD);     
   dev_st7789_send_byte(pstST7789, 0xD0, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x08, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x0E, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x09, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x09, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x05, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x31, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x33, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x48, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x17, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x14, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x15, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x31, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x34, ST7789_DATA);   

   dev_st7789_send_byte(pstST7789, 0xE1, ST7789_CMD);     
   dev_st7789_send_byte(pstST7789, 0xD0, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x08, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x0E, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x09, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x09, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x15, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x31, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x33, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x48, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x17, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x14, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x15, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x31, ST7789_DATA);   
   dev_st7789_send_byte(pstST7789, 0x34, ST7789_DATA);   

   dev_st7789_send_byte(pstST7789, 0x21, ST7789_CMD);

   dev_st7789_send_byte(pstST7789, 0x36, ST7789_CMD); //MX, MY, RGB mode 
 #if (ST7789_ROTATION == 0)
   dev_st7789_send_byte(pstST7789, 0x00, ST7789_DATA);
 #elif (ST7789_ROTATION == 90)
   dev_st7789_send_byte(pstST7789, 0x60, ST7789_DATA);//90
 #elif (ST7789_ROTATION == 180)
   dev_st7789_send_byte(pstST7789, 0xC0, ST7789_DATA);//180
 #elif (ST7789_ROTATION == 270)
   dev_st7789_send_byte(pstST7789, 0xA0, ST7789_DATA);//270
 #endif

   dev_st7789_send_byte(pstST7789, 0x2A, ST7789_CMD); //Column Address Set
   dev_st7789_send_byte(pstST7789, 0x00, ST7789_DATA);
   dev_st7789_send_byte(pstST7789, 0x00, ST7789_DATA); //0
   dev_st7789_send_byte(pstST7789, 0x00, ST7789_DATA);
   dev_st7789_send_byte(pstST7789, 0xEF, ST7789_DATA); //239

   dev_st7789_send_byte(pstST7789, 0x2B, ST7789_CMD); //Row Address Set
   dev_st7789_send_byte(pstST7789, 0x00, ST7789_DATA);
   dev_st7789_send_byte(pstST7789, 0x00, ST7789_DATA); //0
   dev_st7789_send_byte(pstST7789, 0x00, ST7789_DATA);
   dev_st7789_send_byte(pstST7789, 0xEF, ST7789_DATA); //239

   dev_st7789_send_byte(pstST7789, 0x29, ST7789_CMD);

   // LED执行成功
   return DEV_OK;
}



Dev_Ret_t 
dev_st7789_draw_pixel(Dev_ST7789_t *pstST7789, uint16_t u16X,uint16_t u16Y,uint16_t u16Color)
{

   dev_st7789_address_set(pstST7789, u16X,u16Y,u16X,u16Y);//设置光标位置 
   
   dev_st7789_send_half_word(pstST7789, u16Color); //发送颜色数据

   return DEV_OK;
}

Dev_Ret_t 
dev_st7789_fill_rect(Dev_ST7789_t *pstST7789, uint16_t u16XStart, uint16_t u16YStart, 
                    uint16_t u16XEnd, uint16_t u16YEnd, uint16_t u16Color)
{
   uint16_t i;
   uint32_t depth;
   depth = (u16YEnd - u16YStart + 1) * (u16XEnd - u16XStart + 1) * 2;
   dev_st7789_address_set(pstST7789, u16XStart, u16YStart, u16XEnd, u16YEnd);//设置光标位置 
 
    uint32_t u32CacheLen = pstST7789->SW.u32CacheLen;
    uint8_t *pu8Cache = pstST7789->SW.pu8Cache;

   if (depth < u32CacheLen)
   {
      for ( i = 0; i < depth; i += 2)
      {
        pu8Cache[i] = u16Color >> 8;
        pu8Cache[i + 1] = u16Color & 0xFF;
      }
      dev_st7789_send_multi_byte(pstST7789, pu8Cache, depth);
   }
   else
   {
      for ( i = 0; i < u32CacheLen; i += 2)
      {
        pu8Cache[i] = u16Color >> 8;
        pu8Cache[i + 1] = u16Color & 0xFF;
      }
 
      for ( i = 0; i < depth / u32CacheLen; i++)
      {
        dev_st7789_send_multi_byte(pstST7789, pu8Cache, u32CacheLen);
      }
      
      if (depth % u32CacheLen != 0)
      {
        dev_st7789_send_multi_byte(pstST7789, pu8Cache, (depth % u32CacheLen));
      }
      else
      {
         
      }
   }
   return DEV_OK;
}

Dev_Ret_t
dev_st7789_disp_flush(Dev_ST7789_t *pstST7789, uint16_t u16XStart, uint16_t u16YStart, 
                uint16_t u16XEnd, uint16_t u16YEnd, uint16_t* pu16Color)
{
   uint32_t depth;
   depth = (u16YEnd - u16YStart + 1) * (u16XEnd - u16XStart + 1) * 2;
   dev_st7789_address_set(pstST7789, u16XStart, u16YStart, u16XEnd, u16YEnd);//设置光标位置 
 
    
   uint32_t u32CacheLen = pstST7789->SW.u32CacheLen;
   uint8_t *pu8Cache = pstST7789->SW.pu8Cache;

   // 分块发送

   // 块大小
   uint32_t u32BlockNum = depth / u32CacheLen;

   // 剩余大小
   uint32_t u32Remain = depth % u32CacheLen;

   for(uint32_t i=0; i < u32BlockNum; i++)
   {
      for (uint32_t j = 0; j < u32CacheLen; j += 2)
      {
         // 获取颜色
         uint16_t u16Color = *(pu16Color);
         pu16Color++;

         // 写入缓存颜色
         pu8Cache[j] = u16Color >> 8;
         pu8Cache[j + 1] = u16Color & 0xFF;
      }

      // 发送缓存数据
      dev_st7789_send_multi_byte(pstST7789, pu8Cache, u32CacheLen);
   }

   if(u32Remain != 0){
      // 发送剩余数据
      for (uint32_t j = 0; j < u32Remain; j += 2)
      {
         // 获取颜色
         uint16_t u16Color = *(pu16Color);
         pu16Color++;

         // 写入缓存颜色
         pu8Cache[j] = u16Color >> 8;
         pu8Cache[j + 1] = u16Color & 0xFF;
      }

      // 发送缓存数据
      dev_st7789_send_multi_byte(pstST7789,pu8Cache, u32Remain);
   }

   return DEV_OK;
}

Dev_Ret_t
dev_st7789_ioctl(Device_t *pstDevice, uint8_t u8Cmd, void *pvArg)
{
   (void) pvArg;


   // 转换为Dev_Input_t结构体
   Dev_ST7789_t *pstST7789 = GET_CONTEXT(pstDevice, Dev_ST7789_t);

   // 接口为空
//   // todo: 输入参数检查
//   if( NULL == pstST7789->HW.pfnWriteCS || NULL == pstST7789->HW.pfnWriteDC || 
//    NULL == pstST7789->HW.pfnWriteBL || NULL == pstST7789->HW.pfnWriteRST || 
//    NULL == pstST7789->HW.pfnSpiTransmit || 0 == pstST7789->SW.u16Height || 
//    0 == pstST7789->SW.u16Width || NULL == pstST7789->SW.pu8Cache || 
//    0 == pstST7789->SW.u32CacheLen) {return DEV_OK;}

   // 非初始化命令参数不可为空
   if(u8Cmd != ST7789_CMD_INIT && NULL == pvArg)
   {
      return DEV_ARG_NULL;
   }

   // 执行命令
   switch(u8Cmd)
   {
      case ST7789_CMD_INIT:
      {
         // 监视输入
         return dev_st7789_init(pstST7789);
      }

      case ST7789_CMD_DRAW_PIXEL:
      {
         // 获取数据
         Dev_ST7789_Data_t* pstData = (Dev_ST7789_Data_t*)pvArg;

         // 绘制像素
         return dev_st7789_draw_pixel(pstST7789, pstData->u16XStart, pstData->u16YStart, *pstData->pu16Color);
      }

      case ST7789_CMD_FILL_RECT:
      {
         // 获取数据
         Dev_ST7789_Data_t* pstData = (Dev_ST7789_Data_t*)pvArg;
         
         // 填充矩形
         return dev_st7789_fill_rect(pstST7789, pstData->u16XStart, pstData->u16YStart, pstData->u16XEnd, pstData->u16YEnd, *pstData->pu16Color);
      }

      case ST7789_CMD_DISP_FLUSH:
      {
         // 获取数据
         Dev_ST7789_Data_t* pstData = (Dev_ST7789_Data_t*)pvArg;

         // 刷新显示
         return dev_st7789_disp_flush(pstST7789, pstData->u16XStart, pstData->u16YStart, pstData->u16XEnd, pstData->u16YEnd, pstData->pu16Color);
      }

      default:
      {
         // 未知命令
         return DEV_UNKNOWN_IOCTL;
      }
   }
}
